package net.sk.china.platform.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import net.sk.china.platform.constants.Constants;
import net.sk.china.platform.dao.CategoryDao;
import net.sk.china.platform.model.Category;
import net.sk.china.platform.request.category.CategoryRequest;
import net.sk.china.platform.request.category.CategorySearchRequest;
import net.sk.china.platform.response.CategoryTreeResponse;
import net.sk.china.platform.service.CategoryService;
import net.sk.china.common.exception.TalkException;
import net.sk.china.common.request.PageParamRequest;
import net.sk.china.common.utils.TalkUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * CategoryServiceImpl 接口实现
 *
 * +----------------------------------------------------------------------
 * // | Talk To [ 聊来改善地区金融服务环境，助力企业发展 ]
 * // +----------------------------------------------------------------------
 * // | Copyright (c) 2018-2024 聊来 All rights reserved.
 * // +----------------------------------------------------------------------
 * // | Licensed ( <a href="http://www.apache.org/licenses/LICENSE-2.0">apache</a> )
 * // +----------------------------------------------------------------------
 * // | @Author: 聊来 <18970881148@qq.com>
 * // +----------------------------------------------------------------------
 * // | DateTime: 2024/6/3 13:57
 * // +----------------------------------------------------------------------
 */
@Service
public class CategoryServiceImpl extends ServiceImpl<CategoryDao, Category> implements CategoryService {

    @Resource
    private CategoryDao dao;

    /**
     * 分类列表
     * @param request 请求参数
     * @param pageParamRequest 分页参数
     * @return {@code List<Category>}
     */
    @Override
    public List<Category> getList(CategorySearchRequest request, PageParamRequest pageParamRequest) {
        PageHelper.startPage(pageParamRequest.getPage(), pageParamRequest.getLimit());
        LambdaQueryWrapper<Category> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        if(null != request.getPid()){
            lambdaQueryWrapper.eq(Category::getPid, request.getPid());
        }
        if(null != request.getType()){
            lambdaQueryWrapper.eq(Category::getType, request.getType());
        }
        if(ObjectUtil.isNotNull(request.getStatus()) && request.getStatus() >= 0){
            lambdaQueryWrapper.eq(Category::getStatus, request.getStatus().equals(Constants.NUM_ONE));
        }
        if(null != request.getName()){
            lambdaQueryWrapper.like(Category::getName, request.getName());
        }
        lambdaQueryWrapper.orderByDesc(Category::getSort).orderByDesc(Category::getId);
        return dao.selectList(lambdaQueryWrapper);
    }

    /**
     * 新增分类表
     * @param categoryRequest 请求参数
     * @return {@code boolean}
     */
    @Override
    public boolean create(CategoryRequest categoryRequest) {
        // 检测标题是否存在
        if(checkName(categoryRequest.getName(), categoryRequest.getType()) > 0){
            throw new TalkException("此分类已存在");
        }
        Category category = new Category();
        BeanUtils.copyProperties(categoryRequest, category);
        category.setPath(getPathByPId(category.getPid()));
        category.setExtra(category.getExtra());
        return save(category);
    }

    /**
     * 删除分类
     * @param id 数据ID
     * @return {@code Integer}
     */
    @Override
    public Integer delete(Integer id) {
        //查看是否有子类, 物理删除
        if(getChildCountByPid(id) > 0){
            throw new TalkException("当前分类下有子类，请先删除子类！");
        }

        return dao.deleteById(id);
    }

    /**
     * 更新分类
     * @param request 请求数据
     * @param id 分类ID
     * @return {@code boolean}
     */
    @Override
    public boolean update(CategoryRequest request, Integer id) {
        try{
            //修改分类信息
            Category category = new Category();
            BeanUtils.copyProperties(request, category);
            category.setId(id);
            category.setPath(getPathByPId(category.getPid()));

            updateById(category);

            //如状态为关闭，那么所以子集的状态都关闭
            if(!request.getStatus()){
                updateStatusByPid(id, false);
            }else{
                //如是开启，则父类的状态为开启
                updatePidStatusById(id);
            }

            return true;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 带树形结构的无限级分类
     * @param type 分类
     * @param status 状态
     * @param name 名称
     * @return {@code List<CategoryTreeResponse>}
     */
    @Override
    public List<CategoryTreeResponse> getListTree(Integer type, Integer status, String name) {
        return getTree(type, status,name,null);
    }

    /**
     * 带树形结构的无限级分类
     * @param type 分类
     * @param status 状态
     * @param categoryIdList 分类idList
     * @return {@code List<CategoryTreeResponse>}
     */
    @Override
    public List<CategoryTreeResponse> getListTree(Integer type, Integer status, List<Integer> categoryIdList) {
        return getTree(type, status,null, categoryIdList);
    }

    /**
     * 根据分类id集合获取分类数据
     * @param ids id集合字符串
     * @return {@code List<Category>}
     */
    @Override
    public List<Category> getByIds(List<Integer> ids) {
        LambdaQueryWrapper<Category> query = new LambdaQueryWrapper<>();
        query.in(Category::getId, ids);
        return dao.selectList(query);
    }

    /**
     * 更新分类状态
     * @param id 分类ID
     * @return {@code boolean}
     */
    @Override
    public boolean updateStatus(Integer id) {
        Category category = getById(id);
        category.setStatus(!category.getStatus());
        return updateById(category);
    }

    /**
     * 通过id集合获取列表 id => name
     * @param cateIdList List<Integer> id集合
     * @return {@code HashMap<Integer, String>}
     */
    @Override
    public HashMap<Integer, String> getListInId(List<Integer> cateIdList) {
        HashMap<Integer, String> map = new HashMap<>(16);
        List<Category> list = getByIds(cateIdList);
        for (Category category : list){
            map.put(category.getId(), category.getName());
        }

        return map;
    }

    /**
     * 带结构的无限级分类
     * @param type 类型
     * @param status 状态
     * @param name 官架子
     * @param categoryIdList 数据结构类型
     * @return {@code List<CategoryTreeResponse>}
     */
    private List<CategoryTreeResponse> getTree(Integer type, Integer status,String name, List<Integer> categoryIdList) {
        //循环数据，把数据对象变成带list结构的vo
        List<CategoryTreeResponse> treeList = new ArrayList<>();

        LambdaQueryWrapper<Category> query = Wrappers.lambdaQuery();
        query.eq(Category::getType, type);

        if(null != categoryIdList && categoryIdList.size() > 0){
            query.in(Category::getId, categoryIdList);
        }

        if(status >= 0){
            query.eq(Category::getStatus, status);
        }
        if(StringUtils.isNotBlank(name)){
            query.like(Category::getName,name);
        }

        query.orderByDesc(Category::getSort);
        query.orderByAsc(Category::getId);
        List<Category> allTree = dao.selectList(query);
        if(allTree == null){
            return null;
        }
        // 根据名称搜索特殊处理 这里仅仅处理两层搜索后有子父级关系的数据
        if(StringUtils.isNotBlank(name) && allTree.size() >0){
            List<Category> searchCategory = new ArrayList<>();
            List<Integer> categoryIds = allTree.stream().map(Category::getId).collect(Collectors.toList());

            List<Integer> pidList = allTree.stream().filter(c -> c.getPid() > 0 && !categoryIds.contains(c.getPid()))
                    .map(Category::getPid).distinct().collect(Collectors.toList());
            if (CollUtil.isNotEmpty(pidList)) {
                pidList.forEach(pid -> {
                    searchCategory.add(dao.selectById(pid));
                });
            }
            allTree.addAll(searchCategory);
        }

        for (Category category: allTree) {
            CategoryTreeResponse categoryTreeVo = new CategoryTreeResponse();
            BeanUtils.copyProperties(category, categoryTreeVo);
            treeList.add(categoryTreeVo);
        }


        //返回
        Map<Integer, CategoryTreeResponse> map = new HashMap<>(16);
        //ID 为 key 存储到map 中
        for (CategoryTreeResponse categoryTreeVo1 : treeList) {
            map.put(categoryTreeVo1.getId(), categoryTreeVo1);
        }

        List<CategoryTreeResponse> list = new ArrayList<>();
        for (CategoryTreeResponse tree : treeList) {
            //子集ID返回对象，有则添加。
            CategoryTreeResponse tree1 = map.get(tree.getPid());
            if(tree1 != null){
                tree1.getChild().add(tree);
            }else {
                list.add(tree);
            }
        }
        return list;
    }

    /**
     * 修改分类以及子类的状态
     * @param pid Integer
     * @return bool
     */
    private int updateStatusByPid(Integer pid, boolean status) {
        //查看是否有子类
        Category category = new Category();
        category.setStatus(status);

        QueryWrapper<Category> objectQueryWrapper = new QueryWrapper<>();
        objectQueryWrapper.like("path", "/"+pid+"/");
        return dao.update(category, objectQueryWrapper);
    }

    /**
     * 开启父级状态
     * @param id Integer
     */
    private void updatePidStatusById(Integer id) {
        Category category = getById(id);
        List<Integer> categoryIdList = TalkUtil.stringToArrayByRegex(category.getPath(), "/");
        categoryIdList.removeIf(i -> i.equals(0));
        ArrayList<Category> categoryArrayList = new ArrayList<>();
        if(categoryIdList.size() < 1){
            return;
        }
        for (Integer categoryId: categoryIdList) {
            Category categoryVo = new Category();
            categoryVo.setId(categoryId);
            categoryVo.setStatus(true);
            categoryArrayList.add(categoryVo);
        }
        updateBatchById(categoryArrayList);
    }


    /**
     * 获取分类下子类的数量
     * @param pid Integer
     * @return {@code long}
     */
    private long getChildCountByPid(Integer pid) {
        //查看是否有子类
        QueryWrapper<Category> objectQueryWrapper = new QueryWrapper<>();
        objectQueryWrapper.like("path", "/"+pid+"/");
        return dao.selectCount(objectQueryWrapper);
    }

    /**
     * 检测分类名称是否存在
     * @param name String 分类名
     * @param type int 类型
     * @return {@code long}
     */
    private long checkName(String name, Integer type) {
        LambdaQueryWrapper<Category> query = new LambdaQueryWrapper<>();
        query.eq(Category::getName, name);
        query.eq(ObjectUtil.isNotNull(type), Category::getType, type);
        return dao.selectCount(query);
    }

    private String getPathByPId(Integer pid) {
        Category category = getById(pid);
        if(null != category){
            return category.getPath() + pid + "/";
        }
        return null;
    }
}
